home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / tutorials / custEducation / opengl2 / demos / glwstereo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-11  |  13.9 KB  |  559 lines

  1. /*
  2. ** A simple OpenGL stereo application.  Uses the GLw Motif DrawingArea widget
  3. ** with a popup menu.  Includes a simple API for controlling stereo.
  4. **
  5. ** cc -o glwstereo glwstereo.c -lGLw -lXm -lXt -lGL -lXext -lX11 -lm
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <math.h>
  11. #include <sys/time.h>
  12. #include <X11/Xlib.h>
  13. #include <X11/Xutil.h>
  14. #include <X11/StringDefs.h>
  15. #include <Xm/Xm.h>
  16. #include <Xm/Form.h>
  17. #include <Xm/RowColumn.h>
  18. #include <Xm/PushBG.h>
  19. #include <Xm/SeparatoG.h>
  20. #include <X11/GLw/GLwMDrawA.h>
  21.  
  22. /************************************************************************/
  23.  
  24. #include <X11/extensions/SGIStereo.h>
  25.  
  26. static struct stereoStateRec {
  27.     Bool    useSGIStereo;
  28.     Display    *currentDisplay;
  29.     Window    currentWindow;
  30.     GLXContext    currentContext;
  31.     GLenum    currentDrawBuffer;
  32.     int        currentStereoBuffer;
  33.     Bool    enabled;
  34.     char    *stereoCommand;
  35.     char    *restoreCommand;
  36. } stereo;
  37.  
  38. /* call instead of glDrawBuffer */
  39. void
  40. stereoDrawBuffer(GLenum mode)
  41. {
  42.     if (stereo.useSGIStereo) {
  43.     stereo.currentDrawBuffer = mode;
  44.     switch (mode) {
  45.       case GL_FRONT:
  46.       case GL_BACK:
  47.       case GL_FRONT_AND_BACK:
  48.         /*
  49.         ** Simultaneous drawing to both left and right buffers isn't
  50.         ** really possible if we don't have a stereo capable visual.
  51.         ** For now just fall through and use the left buffer.
  52.         */
  53.       case GL_LEFT:
  54.       case GL_FRONT_LEFT:
  55.       case GL_BACK_LEFT:
  56.         stereo.currentStereoBuffer = STEREO_BUFFER_LEFT;
  57.         break;
  58.       case GL_RIGHT:
  59.       case GL_FRONT_RIGHT:
  60.         stereo.currentStereoBuffer = STEREO_BUFFER_RIGHT;
  61.         mode = GL_FRONT;
  62.         break;
  63.       case GL_BACK_RIGHT:
  64.         stereo.currentStereoBuffer = STEREO_BUFFER_RIGHT;
  65.         mode = GL_BACK;
  66.         break;
  67.       default:
  68.         break;
  69.     }
  70.         if (stereo.currentDisplay && stereo.currentWindow) {
  71.         glXWaitGL();  /* sync with GL command stream before calling X */
  72.         XSGISetStereoBuffer(stereo.currentDisplay,
  73.                 stereo.currentWindow,
  74.                 stereo.currentStereoBuffer);
  75.         glXWaitX();   /* sync with X command stream before calling GL */
  76.     }
  77.     }
  78.     glDrawBuffer(mode);
  79. }
  80.  
  81. /* call instead of glClear */
  82. void
  83. stereoClear(GLbitfield mask)
  84. {
  85.     if (stereo.useSGIStereo) {
  86.     GLenum drawBuffer = stereo.currentDrawBuffer;
  87.     switch (drawBuffer) {
  88.       case GL_FRONT:
  89.         stereoDrawBuffer(GL_FRONT_RIGHT);
  90.         glClear(mask);
  91.         stereoDrawBuffer(drawBuffer);
  92.         break;
  93.       case GL_BACK:
  94.         stereoDrawBuffer(GL_BACK_RIGHT);
  95.         glClear(mask);
  96.         stereoDrawBuffer(drawBuffer);
  97.         break;
  98.       case GL_FRONT_AND_BACK:
  99.         stereoDrawBuffer(GL_RIGHT);
  100.         glClear(mask);
  101.         stereoDrawBuffer(drawBuffer);
  102.         break;
  103.       case GL_LEFT:
  104.       case GL_FRONT_LEFT:
  105.       case GL_BACK_LEFT:
  106.       case GL_RIGHT:
  107.       case GL_FRONT_RIGHT:
  108.       case GL_BACK_RIGHT:
  109.       default:
  110.         break;
  111.     }
  112.     }
  113.     glClear(mask);
  114. }
  115.  
  116. /* call after glXMakeCurrent */
  117. void
  118. stereoMakeCurrent(Display *dpy, Window win, GLXContext ctx)
  119. {
  120.     if (stereo.useSGIStereo) {
  121.     if (dpy && (dpy != stereo.currentDisplay)) {
  122.         int event, error;
  123.         /* Make sure new Display supports SGIStereo */
  124.         if (XSGIStereoQueryExtension(dpy, &event, &error) == False) {
  125.         dpy = NULL;
  126.         }
  127.     }
  128.     if (dpy && win && (win != stereo.currentWindow)) {
  129.         /* Make sure new Window supports SGIStereo */
  130.         if (XSGIQueryStereoMode(dpy, win) == X_STEREO_UNSUPPORTED) {
  131.         win = None;
  132.         }
  133.     }
  134.     if (ctx && (ctx != stereo.currentContext)) {
  135.         GLint drawBuffer;
  136.         glGetIntegerv(GL_DRAW_BUFFER, &drawBuffer);
  137.         stereoDrawBuffer((GLenum) drawBuffer);
  138.     }
  139.     stereo.currentDisplay = dpy;
  140.     stereo.currentWindow = win;
  141.     stereo.currentContext = ctx;
  142.     }
  143. }
  144.  
  145. /* call to turn on stereo viewing */
  146. void
  147. stereoEnable(void)
  148. {
  149.     if (!stereo.enabled && stereo.stereoCommand) {
  150.     system(stereo.stereoCommand);
  151.     }
  152.     stereo.enabled = True;
  153. }
  154.  
  155. /* call to turn off stereo viewing */
  156. void
  157. stereoDisable(void)
  158. {
  159.     if (stereo.enabled && stereo.restoreCommand) {
  160.     system(stereo.restoreCommand);
  161.     }
  162.     stereo.enabled = False;
  163. }
  164.  
  165. /* call before using stereo */
  166. void
  167. stereoInit(GLboolean usingStereoVisual, char *stereoCmd, char *restoreCmd)
  168. {
  169.     stereo.useSGIStereo = !usingStereoVisual;
  170.     stereo.currentDisplay = NULL;
  171.     stereo.currentWindow = None;
  172.     stereo.currentContext = NULL;
  173.     stereo.currentDrawBuffer = GL_NONE;
  174.     stereo.currentStereoBuffer = STEREO_BUFFER_NONE;
  175.     stereo.enabled = False;
  176.     if (stereo.stereoCommand) {
  177.     free(stereo.stereoCommand);
  178.     }
  179.     stereo.stereoCommand = stereoCmd ? strdup(stereoCmd) : NULL;
  180.     if (stereo.restoreCommand) {
  181.     free(stereo.restoreCommand);
  182.     }
  183.     stereo.restoreCommand = restoreCmd ? strdup(restoreCmd) : NULL;
  184. }
  185.  
  186. /* call when done using stereo */
  187. void
  188. stereoDone(void)
  189. {
  190.     stereoDisable();
  191.     stereoInit(True, NULL, NULL);
  192. }
  193.  
  194. /************************************************************************/
  195.  
  196. #define APP_CLASS "GLWApp"
  197.  
  198. String fallbackResources[] = {
  199.     /*
  200.     ** Widget resources
  201.     */
  202.     "*sgiMode: True",
  203.     "*useSchemes: all",
  204.     "*title: Simple OpenGL Stereo Demo",
  205.     "*form.width: 300",
  206.     "*form.height: 300",
  207.     /*
  208.     ** Non-Widget (application) resources
  209.     */
  210.     "*stereoCommand: /usr/gfx/setmon -n 640x512_120s",
  211.     "*restoreCommand: /usr/gfx/setmon -n 72HZ",
  212.     "*SGIStereoCommand: /usr/gfx/setmon -n STR_BOT",
  213.     "*SGIRestoreCommand: /usr/gfx/setmon -n 60HZ",
  214.     NULL,
  215. };
  216.  
  217. struct appResourceRec {
  218.     _XtString stereoCommand;
  219.     _XtString restoreCommand;
  220.     _XtString SGIStereoCommand;
  221.     _XtString SGIRestoreCommand;
  222. } appResources;
  223.  
  224. XtResource appResourceList[] = {
  225.     { "stereoCommand",
  226.       XtCString, XtRString, sizeof (_XtString),
  227.       XtOffsetOf(struct appResourceRec, stereoCommand),
  228.       XtRImmediate, (XtPointer) NULL },
  229.     { "restoreCommand",
  230.       XtCString, XtRString, sizeof (_XtString),
  231.       XtOffsetOf(struct appResourceRec, restoreCommand),
  232.       XtRImmediate, (XtPointer) NULL },
  233.     { "SGIStereoCommand",
  234.       XtCString, XtRString, sizeof (_XtString),
  235.       XtOffsetOf(struct appResourceRec, SGIStereoCommand),
  236.       XtRImmediate, (XtPointer) NULL },
  237.     { "SGIRestoreCommand",
  238.       XtCString, XtRString, sizeof (_XtString),
  239.       XtOffsetOf(struct appResourceRec, SGIRestoreCommand),
  240.       XtRImmediate, (XtPointer) NULL },
  241. };
  242.  
  243. XtAppContext appContext;
  244. XtWorkProcId appWorkProcId;
  245. Widget topLevel, form, glw, popup;
  246. GLXContext ctx;
  247. GLboolean animationEnabled = GL_FALSE;
  248. GLboolean stereoEnabled = GL_FALSE;
  249. double lastTime = 0.0;
  250. double rotationRate = 360.0 / 8.0;
  251. double rotation = 0.0;
  252.  
  253. static void
  254. drawCylinder(void)
  255. {
  256.     int numSides = 20;
  257.     double radius = 0.7;
  258.     double stepSize = 2.0*M_PI / numSides;
  259.     int i;
  260.  
  261.     glBegin(GL_TRIANGLE_STRIP);
  262.     for (i=0; i<=numSides; ++i) {
  263.     double a = i * stepSize;
  264.     GLfloat x = cos(a);
  265.     GLfloat y = sin(a);
  266.  
  267.     glNormal3f(x, y, 0.0);
  268.     glVertex3f(x * radius, y * radius, 0.7);
  269.     glNormal3f(x, y, 0.0);
  270.     glVertex3f(x * radius, y * radius, -0.7);
  271.     }
  272.     glEnd();
  273. }
  274.  
  275. static void
  276. initialize(void)
  277. {
  278.     GLfloat lightAmb[4] = { 0.2, 0.2, 0.2, 1.0 };
  279.     GLfloat lightPos[4] = { 1.5, 1.5, 1.5, 1.0 };
  280.     GLfloat matAmbDiff[4] = { 0.30, 0.40, 0.80, 1.0 };
  281.  
  282.     glMatrixMode(GL_MODELVIEW);
  283.     glLoadIdentity();
  284.     glTranslatef(0, 0, -2);
  285.  
  286.     glEnable(GL_DEPTH_TEST);
  287.     glEnable(GL_LIGHTING);
  288.     glEnable(GL_LIGHT0);
  289.     glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb);
  290.     glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
  291.     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  292.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matAmbDiff);
  293.     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  294. }
  295.  
  296. void
  297. stereoFrustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top,
  298.           GLfloat near, GLfloat far, GLfloat eyeDist, GLfloat eyeOffset)
  299. {
  300.     GLfloat eyeShift = (eyeDist - near) * (eyeOffset / eyeDist);
  301.  
  302.     glFrustum(left+eyeShift, right+eyeShift, bottom, top, near, far);
  303.     glTranslatef(-eyeShift, 0.0, 0.0);
  304. }
  305.  
  306. static void
  307. redraw(void)
  308. {
  309.     GLfloat eyeDist = 2.0;
  310.     GLfloat eyeOffset = 0.05;
  311.  
  312.     glPushMatrix();
  313.     glRotated(rotation, 0, 1, 0);
  314.  
  315.     if (stereoEnabled) {
  316.     /*
  317.     ** Draw right-eye view.
  318.     */
  319.     glMatrixMode(GL_PROJECTION);
  320.     glLoadIdentity();
  321.     stereoFrustum(-1, 1, -1, 1, 1, 3, eyeDist, eyeOffset);
  322.     glMatrixMode(GL_MODELVIEW);
  323.  
  324.     stereoDrawBuffer(GL_BACK_RIGHT);
  325.     stereoClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  326.     drawCylinder();
  327.     } else {
  328.     eyeOffset = 0.0;
  329.     }
  330.  
  331.     /*
  332.     ** Draw left-eye view.
  333.     */
  334.     glMatrixMode(GL_PROJECTION);
  335.     glLoadIdentity();
  336.     stereoFrustum(-1, 1, -1, 1, 1, 3, eyeDist, -eyeOffset);
  337.     glMatrixMode(GL_MODELVIEW);
  338.  
  339.     stereoDrawBuffer(GL_BACK_LEFT);
  340.     stereoClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  341.     drawCylinder();
  342.  
  343.     glPopMatrix();
  344.     GLwDrawingAreaSwapBuffers(glw);
  345. }
  346.  
  347. double
  348. getTime(void)
  349. {
  350.     struct timeval time;
  351.     gettimeofday(&time);
  352.     return ((double) time.tv_sec + (double) time.tv_usec * 1E-6);
  353. }
  354.  
  355. static Boolean
  356. animateWP(XtPointer clientData)
  357. {
  358.     double currentTime = getTime();
  359.     double elapsed = currentTime - lastTime;
  360.  
  361.     lastTime = currentTime;
  362.  
  363.     rotation += rotationRate * ((elapsed <= 1.0) ? elapsed : 1.0);
  364.     if (rotation >= 360) rotation -= 360;
  365.  
  366.     redraw();
  367.     return False;
  368. }
  369.  
  370. static void
  371. popupCB(Widget w, XtPointer clientData, XtPointer callData)
  372. {
  373.     int button = (int) clientData;
  374.     Bool needsRedraw = False;
  375.  
  376.     switch (button) {
  377.       case 0:
  378.     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  379.     needsRedraw = True;
  380.     break;
  381.       case 1:
  382.     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  383.     needsRedraw = True;
  384.     break;
  385.       case 2:
  386.     animationEnabled = !animationEnabled;
  387.     if (animationEnabled) {
  388.         lastTime = getTime();
  389.         appWorkProcId = XtAppAddWorkProc(appContext, animateWP, NULL);
  390.     } else {
  391.         XtRemoveWorkProc(appWorkProcId);
  392.     }
  393.     break;
  394.       case 3:
  395.     stereoEnabled = !stereoEnabled;
  396.     if (stereoEnabled) {
  397.         stereoEnable();
  398.     } else {
  399.         stereoDisable();
  400.     }
  401.     needsRedraw = True;
  402.     break;
  403.       case 4:
  404.     stereoDone();
  405.     exit(EXIT_SUCCESS);
  406.     break;
  407.       default:
  408.     break;
  409.     }
  410.     
  411.     if (needsRedraw) {
  412.     redraw();
  413.     }
  414. }
  415.  
  416. static void
  417. popupEH(Widget w, XtPointer clientData, XEvent *event, Boolean *cont)
  418. {
  419.     Widget popup = *((Widget *) clientData);
  420.  
  421.     if ((event->type == ButtonPress) && (event->xbutton.button == Button3)) {
  422.     XmMenuPosition(popup, &event->xbutton);
  423.     XtManageChild(popup);
  424.     }
  425. }
  426.  
  427. static void
  428. exposeCB(Widget w, XtPointer clientData, XtPointer callData)
  429. {
  430.     redraw();
  431. }
  432.  
  433. static void
  434. resizeCB(Widget w, XtPointer clientData, XtPointer callData)
  435. {
  436.     GLwDrawingAreaCallbackStruct *glwcallData = 
  437.     (GLwDrawingAreaCallbackStruct *) callData;
  438.  
  439.     glViewport(0, 0, glwcallData->width, glwcallData->height);
  440.     redraw();
  441. }
  442.  
  443. int
  444. main(int argc, char **argv)
  445. {
  446.     int stereoAttrs[] = {
  447.     GLX_STEREO,
  448.     GLX_RGBA,
  449.     GLX_DOUBLEBUFFER,
  450.     GLX_RED_SIZE, 1,
  451.     GLX_DEPTH_SIZE, 1,
  452.     None,
  453.     };
  454.     int visualAttrs[] = {
  455.     GLX_RGBA,
  456.     GLX_DOUBLEBUFFER,
  457.     GLX_RED_SIZE, 1,
  458.     GLX_DEPTH_SIZE, 1,
  459.     None,
  460.     };
  461.     Display *dpy;
  462.     int scrn;
  463.     XVisualInfo *vis;
  464.     Arg args[10];
  465.     int n;
  466.  
  467.     topLevel = XtOpenApplication(&appContext, APP_CLASS, NULL, 0,
  468.                  &argc, argv, fallbackResources,
  469.                  applicationShellWidgetClass, NULL, 0);
  470.     
  471.     XtGetApplicationResources(topLevel, &appResources, appResourceList,
  472.                   XtNumber(appResourceList), NULL, 0);
  473.  
  474.     dpy = XtDisplay(topLevel);
  475.     scrn = XScreenNumberOfScreen(XtScreen(topLevel));
  476.  
  477.     if ((vis = glXChooseVisual(dpy, scrn, stereoAttrs)) != NULL) {
  478.     /* initialize for use with a stereo capable visual */
  479.     stereoInit(True,
  480.            appResources.stereoCommand,
  481.            appResources.restoreCommand);
  482.  
  483.     } else if ((vis = glXChooseVisual(dpy, scrn, visualAttrs)) != NULL) {
  484.     /* initialize for use without a stereo capable visual */
  485.     stereoInit(False,
  486.            appResources.SGIStereoCommand,
  487.            appResources.SGIRestoreCommand);
  488.  
  489.     /* Force the topLevel widget to maintain a 2:1 aspect ratio */
  490.     n = 0;
  491.     XtSetArg(args[n], XmNminAspectX, 2); n++;
  492.     XtSetArg(args[n], XmNminAspectY, 1); n++;
  493.     XtSetArg(args[n], XmNmaxAspectX, 2); n++;
  494.     XtSetArg(args[n], XmNmaxAspectY, 1); n++;
  495.     XtSetValues(topLevel, args, n);
  496.  
  497.     } else {
  498.     fprintf(stderr, "can't find appropriate visual\n");
  499.     exit(EXIT_FAILURE);
  500.     }
  501.  
  502.     if ((ctx = glXCreateContext(dpy, vis, 0, True)) == NULL) {
  503.     fprintf(stderr, "can't create rendering context\n");
  504.     exit(EXIT_FAILURE);
  505.     }
  506.  
  507.     form = XtCreateManagedWidget("form", xmFormWidgetClass, topLevel, NULL, 0);
  508.  
  509.     n = 0;
  510.     XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  511.     XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  512.     XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  513.     XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  514.     XtSetArg(args[n], GLwNvisualInfo, vis); n++;
  515.     glw = XtCreateManagedWidget("glw", glwMDrawingAreaWidgetClass,
  516.                                 form, args, n);
  517.     XtAddCallback(glw, GLwNexposeCallback, exposeCB, 0);
  518.     XtAddCallback(glw, GLwNresizeCallback, resizeCB, 0);
  519.  
  520.     {
  521.     XmButtonType buttonTypes[] = {
  522.         XmPUSHBUTTON, XmPUSHBUTTON, XmSEPARATOR, XmPUSHBUTTON,
  523.         XmSEPARATOR, XmPUSHBUTTON, XmSEPARATOR, XmPUSHBUTTON,
  524.     };
  525.     XmString buttonLabels[XtNumber(buttonTypes)];
  526.  
  527.     buttonLabels[0] = XmStringCreateLocalized("draw filled");
  528.     buttonLabels[1] = XmStringCreateLocalized("draw lines");
  529.     buttonLabels[2] = NULL;
  530.     buttonLabels[3] = XmStringCreateLocalized("toggle animation");
  531.     buttonLabels[4] = NULL;
  532.     buttonLabels[5] = XmStringCreateLocalized("toggle stereo mode");
  533.     buttonLabels[6] = NULL;
  534.     buttonLabels[7] = XmStringCreateLocalized("quit");
  535.  
  536.     n = 0;
  537.     XtSetArg(args[n], XmNbuttonCount, XtNumber(buttonTypes)); n++;
  538.     XtSetArg(args[n], XmNbuttonType, buttonTypes); n++;
  539.     XtSetArg(args[n], XmNbuttons, buttonLabels); n++;
  540.     XtSetArg(args[n], XmNsimpleCallback, popupCB); n++;
  541.     popup = XmCreateSimplePopupMenu(form, "popup", args, n);
  542.     XtAddEventHandler(form, ButtonPressMask, False, popupEH, &popup);
  543.  
  544.     XmStringFree(buttonLabels[0]);
  545.     XmStringFree(buttonLabels[1]);
  546.     XmStringFree(buttonLabels[3]);
  547.     XmStringFree(buttonLabels[5]);
  548.     XmStringFree(buttonLabels[7]);
  549.     }
  550.  
  551.     XtRealizeWidget(topLevel);
  552.  
  553.     GLwDrawingAreaMakeCurrent(glw, ctx);
  554.     stereoMakeCurrent(dpy, XtWindow(glw), ctx);
  555.     initialize();
  556.  
  557.     XtAppMainLoop(appContext);
  558. }
  559.